﻿using System.Drawing;
using System.Globalization;
using Fuse8.ContentManagementFramework.BizFacade.Services;
using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.SystemFacade.Globalization;
using Fuse8.ContentManagementFramework.Web.Extensions;
using Fuse8.DomainFramework.BusinessService;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Fuse8.ContentManagementFramework.Web.MvcPowered.Components
{
    public static class CmsMediaPickerHtmlHelperExtension
    {
        /// <summary>
        /// Renders CMS media picker
        /// </summary>
        /// <typeparam name="TModel">View model type</typeparam>
        /// <param name="helper">HtmlHelper</param>
        /// <param name="expression">Property expression</param>
        /// <returns></returns>
        public static CmsMediaPicker MediaPicker<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, int>> expression)
        {
            var property = helper.GetClientFullName(expression);
            var elementId = helper.GetClientIdFor(expression).ToString();
            var func = expression.Compile();
            var value = func(helper.ViewData.Model);
            return new CmsMediaPicker(property, value, elementId);
        }

        /// <summary>
        /// Renders CMS media picker
        /// </summary>
        /// <param name="helper">HtmlHelper</param>
        /// <param name="property">Property name</param>
        /// <param name="value">Value</param>
        /// <returns></returns>
        public static CmsMediaPicker MediaPicker(this HtmlHelper helper, string property, int value)
        {
            return new CmsMediaPicker(property, value);
        }
    }

    public class CmsMediaPicker : IHtmlString
    {
        private string[] _mediaTypes;
        private string _wrapperElement;
        private RouteValueDictionary _attributes;
        private bool _canUploadMedia;
        private readonly int _value;
        private readonly string _elementId;
        private readonly string _elementName;
        private CmsMediaFile _mediaContent;
        private bool _withPreview;
        private Size _previewSize;

        public CmsMediaPicker(string property, int value, string elementId = null)
        {
            _elementName = property;
            _elementId = elementId ?? property;

            _value = value;
        }

        public CmsMediaPicker FileTypes(string[] mediaTypes)
        {
            _mediaTypes = mediaTypes;
            return this;
        }

        public CmsMediaPicker CanUploadMedia(bool value = false)
        {
            _canUploadMedia = value;
            return this;
        }

        public CmsMediaPicker Wrapper(string wrapperElement)
        {
            _wrapperElement = wrapperElement;
            return this;
        }

        public CmsMediaPicker WithPreview(Size size)
        {
            _withPreview = true;
            _previewSize = size;
            return this;
        }

        public CmsMediaPicker Attributes(object htmlAttributes)
        {
            if (htmlAttributes != null)
            {
                _attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            }

            return this;
        }

        private CmsMediaFile MediaContent
        {
            get
            {
                return _mediaContent ?? (_mediaContent = _value > 0 ? new CmsMediaFileService().FindOne(_value) : null);
            }
        }

        protected MvcHtmlString Render()
        {
            var mediaIdElementBuilder = new TagBuilder("input");
            var mediaContentControl = new TagBuilder("input");
            var uploadButtom = new TagBuilder("button");
            var selectBtn = new TagBuilder("a");
            var removeBtn = new TagBuilder("a");
            var getTextManager = GlobalizationFacade.Current.WithDomain("cms_Media", CultureInfo.CurrentUICulture);

            mediaIdElementBuilder.Attributes.Add("id", _elementId);
            mediaIdElementBuilder.Attributes.Add("name", _elementName);
            mediaIdElementBuilder.Attributes.Add("type", "hidden");
            mediaIdElementBuilder.Attributes.Add("value", _value.ToString());

            mediaContentControl.AddCssClass("js-mediapicker-content-title b-mediapicker__input text valid");
            if (_canUploadMedia)
            {
                mediaContentControl.AddCssClass("b-mediapicker__input-short");
            }
            mediaContentControl.Attributes.Add("type", "text");
            mediaContentControl.Attributes.Add("disabled", "disabled");
            mediaContentControl.Attributes.Add("value", MediaContent != null ? HttpUtility.HtmlAttributeEncode(MediaContent.OriginalFileName) : "");

            uploadButtom.AddCssClass("js-mediapicker-browse-btn b-button b-button_small");
            uploadButtom.Attributes.Add("data-element-id", _elementId);
            uploadButtom.SetInnerText(getTextManager.GetText("Upload"));

            selectBtn.AddCssClass("js-mediapicker-select-btn");
            selectBtn.Attributes.Add("href", "#");
            selectBtn.Attributes.Add("data-element-id", _elementId);
            if (_mediaTypes != null && _mediaTypes.Any())
            {
                selectBtn.Attributes.Add("data-media-types", string.Join(",", _mediaTypes));
            }

            selectBtn.SetInnerText(getTextManager.GetText("select an existing media item"));

            removeBtn.AddCssClass("js-mediapicker-remove b-icon b-icon_delete_custom-picker b-icon_delete_mediapicker");
            removeBtn.Attributes.Add("href", "#");
            removeBtn.Attributes.Add("data-element-id", _elementId);
            removeBtn.SetInnerText(getTextManager.GetText("Remove"));

            if (MediaContent == null)
            {
                removeBtn.Attributes.Add("style", "display:none;");
            }

            var container = GetContainer(_elementId);
            var controlsContainer = new TagBuilder("div");
            var controlsHtmlBuilder = new StringBuilder();

            controlsContainer.AddCssClass("g-clear");

            if (_withPreview)
            {
                string source = "";
                string style = "display: none";
                if (MediaContent != null)
                {
                    source = MediaContent.LinkedFileName;
                    style = "";
                }
                controlsHtmlBuilder.AppendFormat("<img src=\"/admin/media/{0}?w={1}&h={2}\" class=\"js-mediapicker-img mediapicker-preview-thumb\" style=\"{3}\"/>",
                    source,
                    _previewSize.Width,
                    _previewSize.Height,
                    style);
            }

            controlsHtmlBuilder.AppendLine(mediaIdElementBuilder.ToString(TagRenderMode.SelfClosing));
            controlsHtmlBuilder.AppendLine(mediaContentControl.ToString());

            if (_canUploadMedia)
            {
                controlsHtmlBuilder.AppendLine(uploadButtom.ToString());
                selectBtn.SetInnerText(getTextManager.GetText("or select an existing media item"));
            }

            controlsHtmlBuilder.AppendLine(removeBtn.ToString());

            controlsContainer.InnerHtml = controlsHtmlBuilder.ToString();

            container.InnerHtml = controlsContainer.ToString() + selectBtn;

            return new MvcHtmlString(container.ToString());
        }

        private TagBuilder GetContainer(string elementId)
        {
            EnsureWrapping();

            var controlContainer = new TagBuilder(_wrapperElement);

            controlContainer.AddCssClass("js-mediapicker-container b-form b-mediapicker-wrap");

            if (_attributes != null)
            {
                controlContainer.MergeAttributes(_attributes);
            }

            return controlContainer;
        }

        private void EnsureWrapping()
        {
            if (string.IsNullOrEmpty(_wrapperElement))
            {
                _wrapperElement = "div";
            }
        }

        public string ToHtmlString()
        {
            return Render().ToHtmlString();
        }
    }
}